package person.tavion.securitydemo.core.security;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import person.tavion.securitydemo.core.security.handler.MyLoginFailureHandler;

import java.io.IOException;

@Configuration
//@EnableWebSecurity // 开启springSecurity自定义配置，在springboot项目中，可以省略该注解，因为它自动引入了该注解
public class WebSecurityConfig {
	@Bean
	PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

	@Bean
	public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
		InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
		manager.createUser(User.builder()
				.username("admin")
				.password("admin")
				.passwordEncoder(text->passwordEncoder.encode(text))
				.roles("USER")
				.build());
		return manager;
	}

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http.authorizeHttpRequests(
				authorize -> authorize
						// 禁止使用 /**
						// 放开不用认证的请求

						.requestMatchers("/login").permitAll()
						.anyRequest()
						//已认证的请求会被自动授权
						.authenticated()



				)
				.sessionManagement(sessionManagementCustomizer->{
//					用户登录成功后，信息保存在服务器Session中。SpringSecurity提供了4种方式控制会话创建。
//					* always：如果一个会话尚不存在，将始终创建一个会话。
//					* ifRequired：仅在需要时创建会话，默认。
//					* never：框架永远不会创建会话本身，但如果它已经存在，它将使用一个。
//					* stateless：不会创建或使用任何会话，完全无状态。
					sessionManagementCustomizer.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
				})


		;

		http.formLogin((formLogin) ->
						formLogin
								.usernameParameter("username")
								.passwordParameter("password")
								.loginPage("/login")	// 登录页
//								.failureUrl("/authentication/login?failed")	//登录失败跳转页
//								.loginProcessingUrl("/authentication/login/process") //登录表单提交的URL地址
//								.successHandler()	// 登录成功 handler
//								.failureHandler(new MyLoginFailureHandler())	// 登录失败 handler


//				.successForwardUrl()是转发，所以你原来使用的是表单的请求方式是POST，转发到其它资源的方式也应该是POST
//				.defaultSuccessUrl是重定向,响应资源对应请求类型好像必须为GET(自己验证过)
//								.successForwardUrl("/test") // 所以这里是POST请求
								.defaultSuccessUrl("/test")

		);

		http.logout(logout->{
//			logout.logoutSuccessHandler() // 退出登录成功 handler
		});

		http.exceptionHandling(exception->{
//			exception.authenticationEntryPoint()// 请求未认证的处理
		});
		// 关闭”crsf攻击“防御 ,登录时会带参数crsf
//		http.csrf(csrf -> csrf.disable());
		// 开启跨域访问
		http.cors(cors->cors.disable());



		return http.build();

	}
}